﻿using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Notoric.ViewModel;

namespace Notoric.Gui.Windows
{
    /// <summary>
    /// Interaction logic for MusicSectionPropertiesDialog.xaml
    /// </summary>
    public partial class MusicSectionPropertiesDialog : Window
    {
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="MusicSectionPropertiesDialog"/> class.
        /// </summary>
        public MusicSectionPropertiesDialog()
        {
            InitializeComponent();
        }

        #endregion

        #region Dependency Properties Identifiers

        /// <summary>
        /// Identifies the <see cref="Compositions"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty CompositionsProperty = DependencyProperty.Register(
            "Compositions", typeof(IProjectExplorerItem), typeof(MusicSectionPropertiesDialog)
            );

        /// <summary>
        /// Identifies the <see cref="FirstMeasure"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty FirstMeasureProperty = DependencyProperty.Register(
            "FirstMeasure", typeof(ushort), typeof(MusicSectionPropertiesDialog),
            new PropertyMetadata((ushort)1)
            );

        /// <summary>
        /// Identifies the <see cref="LastMeasure"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty LastMeasureProperty = DependencyProperty.Register(
            "LastMeasure", typeof(ushort), typeof(MusicSectionPropertiesDialog),
            new PropertyMetadata((ushort)1)
            );

        /// <summary>
        /// Identifies the <see cref="MeasuresPerSystem"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty MeasuresPerSystemProperty = DependencyProperty.Register(
            "MeasuresPerSystem", typeof(ushort), typeof(MusicSectionPropertiesDialog),
            new PropertyMetadata((ushort)5)
            );

        /// <summary>
        /// Identifies the <see cref="SelectedComposition"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty SelectedCompositionProperty = DependencyProperty.Register(
            "SelectedComposition", typeof(ViewModel.Elements.Composition), typeof(MusicSectionPropertiesDialog)
            );

        /// <summary>
        /// Identifies the <see cref="SelectedParts"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty SelectedPartsProperty = DependencyProperty.Register(
            "SelectedParts", typeof(ObservableCollection<ViewModel.Elements.PartDescriptor>), typeof(MusicSectionPropertiesDialog),
            new PropertyMetadata(new ObservableCollection<ViewModel.Elements.PartDescriptor>())
            );

        #endregion

        #region Event Handlers

        /// <summary>
        /// Occurs when a part has been selected to be presented in the created music section.
        /// </summary>
        /// <param name="sender">Object where the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void CheckBox_Checked(object sender, RoutedEventArgs e)
        {
            var part = ((CheckBox)sender).DataContext as ViewModel.Elements.PartDescriptor;

            var index = 0;
            foreach (var liPart in PART_PresentedParts.Items)
            {
                if (liPart == part)
                    break;
                if (SelectedParts.Contains(liPart))
                    ++index;
            }

            if (!SelectedParts.Contains(part))
                SelectedParts.Insert(index, part);
        }

        /// <summary>
        /// Occurs when a part has been removed from the created music section.
        /// </summary>
        /// <param name="sender">Object where the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
        {
            var part = ((CheckBox)sender).DataContext as ViewModel.Elements.PartDescriptor;

            SelectedParts.Remove(part);
        }

        /// <summary>
        /// Occurs when the selected composition has changed.
        /// </summary>
        /// <param name="sender">Object where the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void PART_CompositionsTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            SelectedParts.Clear();

            if (PART_CompositionsTree.SelectedItem is ViewModel.Elements.Composition)
            {
                SelectedComposition = (ViewModel.Elements.Composition)PART_CompositionsTree.SelectedItem;

                foreach (var part in SelectedComposition.Parts)
                    SelectedParts.Add(part);
                PART_PresentedParts.ItemsSource = SelectedComposition.Parts;

                if (SelectedComposition.MeasuresCount > 0)
                {
                    PART_FirstMeasure.Maximum = SelectedComposition.MeasuresCount;
                    PART_LastMeasure.Maximum = SelectedComposition.MeasuresCount;
                    PART_FirstMeasure.Value = 1;
                    PART_LastMeasure.Value = 1;
                    PART_MeasuresPerSystem.Value = 5;

                    PART_FirstMeasure.IsEnabled = true;
                    PART_LastMeasure.IsEnabled = true;
                    PART_MeasuresPerSystem.IsEnabled = true;

                    PART_OK.IsEnabled = true;
                }
                else
                {
                    PART_FirstMeasure.IsEnabled = false;
                    PART_LastMeasure.IsEnabled = false;
                    PART_MeasuresPerSystem.IsEnabled = false;

                    PART_OK.IsEnabled = false;
                }
            }
            else
            {
                SelectedComposition = null;

                PART_PresentedParts.ItemsSource = null;
                PART_FirstMeasure.IsEnabled = false;
                PART_LastMeasure.IsEnabled = false;
                PART_MeasuresPerSystem.IsEnabled = false;

                PART_OK.IsEnabled = false;
            }
        }

        /// <summary>
        /// Occurs when the user clicks the OK button.
        /// </summary>
        /// <param name="sender">Object where the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void PART_OK_Click(object sender, RoutedEventArgs e)
        {
            if (FirstMeasure < PART_FirstMeasure.Minimum)
                FirstMeasure = (ushort)PART_FirstMeasure.Minimum;
            else if (FirstMeasure > PART_FirstMeasure.Maximum)
                FirstMeasure = (ushort)PART_FirstMeasure.Maximum;

            if (LastMeasure < PART_LastMeasure.Minimum)
                LastMeasure = (ushort)PART_LastMeasure.Minimum;
            else if (LastMeasure > PART_LastMeasure.Maximum)
                LastMeasure = (ushort)PART_LastMeasure.Maximum;

            if (!ViewModel.Elements.MusicSection.ValidCompositionPart(SelectedComposition, SelectedParts, FirstMeasure, LastMeasure))
            {
                MessageBox.Show(
                    "The selected composition part cannot be presented in a music section, because it contains empty measures. Please, select another part of the composition or fill the measures first.",
                    "Notoric",
                    MessageBoxButton.OK,
                    MessageBoxImage.Exclamation
                    );
                return;
            }

            this.DialogResult = true;
        }

        /// <summary>
        /// Occurs when the user clicks the Cancel button.
        /// </summary>
        /// <param name="sender">Object where the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void PART_Cancel_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the root of the compositions hierarchy.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="IProjectExplorerItem"/>
        /// </para>
        /// <para>
        /// The root of the compositions hierarchy.
        /// </para>
        /// </value>
        public IProjectExplorerItem Compositions
        {
            get { return (IProjectExplorerItem)GetValue(CompositionsProperty); }
            set { SetValue(CompositionsProperty, value); }
        }

        /// <summary>
        /// Gets or sets the first measure presented in the music section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="UInt16"/>
        /// </para>
        /// <para>
        /// The first measure presented in the music section.
        /// </para>
        /// </value>
        public ushort FirstMeasure
        {
            get { return (ushort)GetValue(FirstMeasureProperty); }
            set { SetValue(FirstMeasureProperty, value); }
        }

        /// <summary>
        /// Gets or sets the last measure presented in the music section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="UInt16"/>
        /// </para>
        /// <para>
        /// The last measure presented in the music section.
        /// </para>
        /// </value>
        public ushort LastMeasure
        {
            get { return (ushort)GetValue(LastMeasureProperty); }
            set { SetValue(LastMeasureProperty, value); }
        }

        /// <summary>
        /// Gets or sets the measures per system in the music section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="UInt16"/>
        /// </para>
        /// <para>
        /// The measures per system in the music section.
        /// </para>
        /// </value>
        public ushort MeasuresPerSystem
        {
            get { return (ushort)GetValue(MeasuresPerSystemProperty); }
            set { SetValue(MeasuresPerSystemProperty, value); }
        }

        /// <summary>
        /// Gets or sets the composition presented in the music section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="ViewModel.Elements.Composition"/>
        /// </para>
        /// <para>
        /// The composition presented in the music section.
        /// </para>
        /// </value>
        public ViewModel.Elements.Composition SelectedComposition
        {
            get { return (ViewModel.Elements.Composition)GetValue(SelectedCompositionProperty); }
            set { SetValue(SelectedCompositionProperty, value); }
        }

        /// <summary>
        /// Gets or sets the parts selected for the music section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="ObservableCollection{T}"/> of <see cref="ViewModel.Elements.PartDescriptor"/>
        /// </para>
        /// <para>
        /// The collection of parts that will be presented in the music section.
        /// </para>
        /// </value>
        public ObservableCollection<ViewModel.Elements.PartDescriptor> SelectedParts
        {
            get { return (ObservableCollection<ViewModel.Elements.PartDescriptor>)GetValue(SelectedPartsProperty); }
            set { SetValue(SelectedPartsProperty, value); }
        }

        #endregion
    }
}
